//! 崩溃恢复测试
//! 
//! 本模块测试数据库在各种故障场景下的恢复能力

use super::transaction::*;
use super::page::PageManager;
use super::tuple::RowId;
use std::sync::Arc;
use std::fs;
use std::path::Path;
use tempfile::tempdir;

/// 崩溃恢复测试套件
pub struct RecoveryTestSuite {
    temp_dir: tempfile::TempDir,
}

impl RecoveryTestSuite {
    /// 创建新的恢复测试套件
    pub fn new() -> Result<Self, crate::Error> {
        let temp_dir = tempdir().map_err(|e| crate::Error::storage(format!("创建临时目录失败: {}", e)))?;
        
        Ok(Self {
            temp_dir,
        })
    }
    
    /// 测试WAL恢复机制
    pub fn test_wal_recovery(&self) -> Result<(), crate::Error> {
        println!("🧪 测试WAL恢复机制...");
        
        let wal_path = self.temp_dir.path().join("recovery_test.wal").to_string_lossy().to_string();
        
        // 第一阶段：创建一些事务并写入WAL
        {
            let page_manager = Arc::new(PageManager::new(1000));
            let tx_manager = TransactionManager::new(page_manager, wal_path.clone())?;
            
            // 创建并提交几个事务
            for i in 0..5 {
                let tx = tx_manager.begin_transaction(IsolationLevel::ReadCommitted, false)?;
                
                // 模拟数据变更
                let mut write_set = tx.write_set.write();
                write_set.insert(RowId::new(i + 1000, 0));
                drop(write_set);
                
                tx_manager.commit_transaction(tx)?;
            }
            
            // 创建一个未提交的事务
            let tx = tx_manager.begin_transaction(IsolationLevel::ReadCommitted, false)?;
            let mut write_set = tx.write_set.write();
            write_set.insert(RowId::new(9999, 0));
            drop(write_set);
            // 故意不提交这个事务
            
            // 强制刷新WAL
            tx_manager.get_wal_manager().flush()?;
            
            let initial_lsn = tx_manager.get_wal_manager().get_current_lsn();
            println!("  初始LSN: {}", initial_lsn);
        } // tx_manager被销毁，模拟系统崩溃
        
        // 第二阶段：模拟系统重启和恢复
        {
            let page_manager = Arc::new(PageManager::new(1000));
            let new_tx_manager = TransactionManager::new(page_manager.clone(), wal_path.clone())?;
            
            // 执行恢复
            new_tx_manager.get_wal_manager().recover(&page_manager)?;
            
            let recovered_lsn = new_tx_manager.get_wal_manager().get_current_lsn();
            println!("  恢复后LSN: {}", recovered_lsn);
            
            // 验证恢复后的状态
            assert!(recovered_lsn > 0);
            
            // 验证可以继续正常操作
            let tx = new_tx_manager.begin_transaction(IsolationLevel::ReadCommitted, false)?;
            let mut write_set = tx.write_set.write();
            write_set.insert(RowId::new(2000, 0));
            drop(write_set);
            new_tx_manager.commit_transaction(tx)?;
        }
        
        println!("✅ WAL恢复测试通过");
        Ok(())
    }
    
    /// 测试检查点恢复
    pub fn test_checkpoint_recovery(&self) -> Result<(), crate::Error> {
        println!("🧪 测试检查点恢复...");
        
        let wal_path = self.temp_dir.path().join("checkpoint_test.wal").to_string_lossy().to_string();
        
        // 第一阶段：创建事务并执行检查点
        {
            let page_manager = Arc::new(PageManager::new(1000));
            let tx_manager = TransactionManager::new(page_manager, wal_path.clone())?;
            
            // 创建多个事务
            for i in 0..10 {
                let tx = tx_manager.begin_transaction(IsolationLevel::ReadCommitted, false)?;
                
                let mut write_set = tx.write_set.write();
                write_set.insert(RowId::new(i + 3000, 0));
                drop(write_set);
                
                tx_manager.commit_transaction(tx)?;
            }
            
            // 执行检查点
            let checkpoint_manager = tx_manager.get_wal_manager().get_checkpoint_manager();
            if checkpoint_manager.start_checkpoint() {
                let current_lsn = tx_manager.get_wal_manager().get_current_lsn();
                checkpoint_manager.finish_checkpoint(current_lsn);
                println!("  检查点完成，LSN: {}", current_lsn);
            }
            
            // 在检查点后创建更多事务
            for i in 10..15 {
                let tx = tx_manager.begin_transaction(IsolationLevel::ReadCommitted, false)?;
                
                let mut write_set = tx.write_set.write();
                write_set.insert(RowId::new(i + 3000, 0));
                drop(write_set);
                
                tx_manager.commit_transaction(tx)?;
            }
            
            tx_manager.get_wal_manager().flush()?;
        }
        
        // 第二阶段：模拟崩溃后恢复
        {
            let page_manager = Arc::new(PageManager::new(1000));
            let new_tx_manager = TransactionManager::new(page_manager.clone(), wal_path.clone())?;
            
            // 执行恢复
            new_tx_manager.get_wal_manager().recover(&page_manager)?;
            
            // 验证恢复成功
            let stats = new_tx_manager.get_stats();
            println!("  恢复后统计: 总事务={}, 已提交={}", stats.total_transactions, stats.committed_transactions);
        }
        
        println!("✅ 检查点恢复测试通过");
        Ok(())
    }
    
    /// 测试部分写入恢复
    pub fn test_partial_write_recovery(&self) -> Result<(), crate::Error> {
        println!("🧪 测试部分写入恢复...");
        
        let wal_path = self.temp_dir.path().join("partial_write_test.wal").to_string_lossy().to_string();
        
        // 第一阶段：创建事务并模拟部分写入
        {
            let page_manager = Arc::new(PageManager::new(1000));
            let tx_manager = TransactionManager::new(page_manager, wal_path.clone())?;
            
            // 创建一个大事务
            let tx = tx_manager.begin_transaction(IsolationLevel::ReadCommitted, false)?;
            
            // 写入大量数据
            let mut write_set = tx.write_set.write();
            for i in 0..100 {
                write_set.insert(RowId::new(i + 4000, 0));
            }
            drop(write_set);
            
            // 开始提交但不完成（模拟部分写入）
            // 这里我们只写入WAL但不完成事务
            tx_manager.get_wal_manager().write_transaction_begin(tx.id)?;
            
            // 写入一些记录
            for i in 0..50 {
                let record_type = WalRecordType::Insert {
                    page_id: 1,
                    slot_id: i,
                    old_data: None,
                    new_data: vec![1, 2, 3, 4],
                };
                tx_manager.get_wal_manager().write_record(tx.id, record_type)?;
            }
            
            // 故意不写入提交记录，模拟崩溃
            tx_manager.get_wal_manager().flush()?;
        }
        
        // 第二阶段：恢复并验证未完成的事务被回滚
        {
            let page_manager = Arc::new(PageManager::new(1000));
            let new_tx_manager = TransactionManager::new(page_manager.clone(), wal_path.clone())?;
            
            // 执行恢复
            new_tx_manager.get_wal_manager().recover(&page_manager)?;
            
            // 验证未完成的事务被正确处理
            let stats = new_tx_manager.get_stats();
            println!("  恢复后统计: 总事务={}, 已提交={}, 已回滚={}", 
                stats.total_transactions, stats.committed_transactions, stats.rolled_back_transactions);
            
            // 验证系统可以继续正常工作
            let tx = new_tx_manager.begin_transaction(IsolationLevel::ReadCommitted, false)?;
            let mut write_set = tx.write_set.write();
            write_set.insert(RowId::new(5000, 0));
            drop(write_set);
            new_tx_manager.commit_transaction(tx)?;
        }
        
        println!("✅ 部分写入恢复测试通过");
        Ok(())
    }
    
    /// 测试WAL文件损坏恢复
    pub fn test_corrupted_wal_recovery(&self) -> Result<(), crate::Error> {
        println!("🧪 测试WAL文件损坏恢复...");
        
        let wal_path = self.temp_dir.path().join("corrupted_test.wal").to_string_lossy().to_string();
        
        // 第一阶段：创建正常的WAL文件
        {
            let page_manager = Arc::new(PageManager::new(1000));
            let tx_manager = TransactionManager::new(page_manager, wal_path.clone())?;
            
            // 创建一些事务
            for i in 0..3 {
                let tx = tx_manager.begin_transaction(IsolationLevel::ReadCommitted, false)?;
                
                let mut write_set = tx.write_set.write();
                write_set.insert(RowId::new(i + 6000, 0));
                drop(write_set);
                
                tx_manager.commit_transaction(tx)?;
            }
            
            tx_manager.get_wal_manager().flush()?;
        }
        
        // 第二阶段：模拟WAL文件损坏
        {
            if Path::new(&wal_path).exists() {
                // 读取原文件内容
                let original_content = fs::read(&wal_path).unwrap();
                
                // 截断文件（模拟部分损坏）
                let truncated_content = &original_content[..original_content.len() / 2];
                fs::write(&wal_path, truncated_content).unwrap();
                
                println!("  模拟WAL文件损坏：从{}字节截断到{}字节", 
                    original_content.len(), truncated_content.len());
            }
        }
        
        // 第三阶段：尝试恢复损坏的WAL
        {
            let page_manager = Arc::new(PageManager::new(1000));
            let result = TransactionManager::new(page_manager.clone(), wal_path.clone());
            
            match result {
                Ok(tx_manager) => {
                    // 如果成功创建，尝试恢复
                    let recovery_result = tx_manager.get_wal_manager().recover(&page_manager);
                    println!("  恢复结果: {:?}", recovery_result.is_ok());
                    
                    // 验证系统仍然可以工作
                    let tx = tx_manager.begin_transaction(IsolationLevel::ReadCommitted, false)?;
                    let mut write_set = tx.write_set.write();
                    write_set.insert(RowId::new(7000, 0));
                    drop(write_set);
                    tx_manager.commit_transaction(tx)?;
                }
                Err(e) => {
                    println!("  检测到WAL损坏: {}", e);
                    
                    // 删除损坏的WAL文件并重新创建
                    fs::remove_file(&wal_path).ok();
                    let tx_manager = TransactionManager::new(page_manager, wal_path)?;
                    
                    // 验证可以重新开始
                    let tx = tx_manager.begin_transaction(IsolationLevel::ReadCommitted, false)?;
                    let mut write_set = tx.write_set.write();
                    write_set.insert(RowId::new(8000, 0));
                    drop(write_set);
                    tx_manager.commit_transaction(tx)?;
                }
            }
        }
        
        println!("✅ WAL文件损坏恢复测试通过");
        Ok(())
    }
    
    /// 运行完整的恢复测试套件
    pub fn run_full_recovery_test_suite(&self) -> Result<(), crate::Error> {
        println!("🚀 开始崩溃恢复测试套件...");
        println!("=====================================");
        
        self.test_wal_recovery()?;
        self.test_checkpoint_recovery()?;
        self.test_partial_write_recovery()?;
        self.test_corrupted_wal_recovery()?;
        
        println!("=====================================");
        println!("🎉 崩溃恢复测试套件全部通过！");
        
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_wal_recovery() {
        let test_suite = RecoveryTestSuite::new().unwrap();
        test_suite.test_wal_recovery().unwrap();
    }
    
    #[test]
    fn test_checkpoint_recovery() {
        let test_suite = RecoveryTestSuite::new().unwrap();
        test_suite.test_checkpoint_recovery().unwrap();
    }
    
    #[test]
    fn test_partial_write_recovery() {
        let test_suite = RecoveryTestSuite::new().unwrap();
        test_suite.test_partial_write_recovery().unwrap();
    }
    
    #[test]
    fn test_corrupted_wal_recovery() {
        let test_suite = RecoveryTestSuite::new().unwrap();
        test_suite.test_corrupted_wal_recovery().unwrap();
    }
    
    #[test]
    fn test_full_recovery_suite() {
        let test_suite = RecoveryTestSuite::new().unwrap();
        test_suite.run_full_recovery_test_suite().unwrap();
    }
}
